package com.intretech.umsin.oss.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.intretech.umsin.common.web.ApiResult;
import com.intretech.umsin.openoffice.OpenOffice;
import com.intretech.umsin.oss.config.OssServiceFactory;
import com.intretech.umsin.oss.param.FileInfoParam;
import com.intretech.umsin.oss.param.UploadParam;
import com.intretech.umsin.oss.service.FileService;
import com.intretech.umsin.oss.vo.FileInfoVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @version V1.0
 * @ClassName: OSSController
 * @Description: OSSController 服务实现
 * @author: 李启联
 * @date: 2022-04-25 16:58
 * @Copyright: Copyright (c) 2022
 */
@RestController
@RequestMapping("/oss")
@Api(tags = "model-file-center")
public class OSSController {

    @Autowired
    private OssServiceFactory ossServiceFactory;

    @Autowired
    private OpenOffice openOffice;

    /**
     * 获得文件分页列表
     * @param fileInfoParam 查询实体参数
     * @param pageNo 查询返回的页码
     * @param pageSize 每页显示的条目数
     * @return
     */
    @PostMapping("/page/{pageNo}/{pageSize}")
    @ApiOperation(value = "查询返回文件分页对象", notes = "查询返回文件分页对象")
    public ApiResult<IPage<FileInfoVo>> getFileList(@RequestBody FileInfoParam fileInfoParam, @PathVariable Integer pageNo, @PathVariable Integer pageSize){
        Function<FileInfoParam,IPage<FileInfoVo>> fun = p -> ossServiceFactory.createFileService().findByPageResult(p,pageNo,pageSize);
        return ApiResult.responseFor(fun,fileInfoParam);
    }


    /**
     * 上传文件
     * @param file 上传的源文件
     * @param businessId 业务单主键标识
     * @param path 存放路径
     * @param userDefine 用户自定义属性
     * @param ifPublic 是否公开
     * @return
     * @throws Exception
     */
    @PostMapping("/upload")
    @ApiOperation(value = "上传文件", notes = "上传文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "businessId",value = "业务单主键标识",dataType = "String"),
            @ApiImplicitParam(name = "path",value = "存放路径", dataType = "String"),
            @ApiImplicitParam(name = "userDefine",value = "用户自定义属性",dataType = "String"),
            @ApiImplicitParam(name = "ifPublic",value = "是否公开",dataType = "Boolean")
    })
    public ApiResult<FileInfoVo> upload(@RequestParam("file") MultipartFile file, String businessId,String path,String userDefine ,Boolean ifPublic) throws Exception {
        BiFunction<MultipartFile,UploadParam,FileInfoVo> fun = (p1, p2) -> {
            try {
                return ossServiceFactory.createFileService().upload(p1,p2);
            } catch (Exception e) {
                return null;
            }
        };
        return ApiResult.responseFor(fun,file,new UploadParam(path,businessId,userDefine,ifPublic));
    }

    /**
     * 上传多个文件
     * @param files 上传的源文件
     * @param businessId 业务单主键标识
     * @param path 存放路径
     * @param userDefine 用户自定义属性
     * @param ifPublic 是否公开
     * @return
     * @throws Exception
     */
    @PostMapping("/uploads")
    @ApiOperation(value = "上传多个文件", notes = "上传多个文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "businessId",value = "业务单主键标识",dataType = "String"),
            @ApiImplicitParam(name = "path",value = "存放路径", dataType = "String"),
            @ApiImplicitParam(name = "userDefine",value = "用户自定义属性",dataType = "String"),
            @ApiImplicitParam(name = "ifPublic",value = "是否公开",dataType = "Boolean")
    })
    public ApiResult<List<FileInfoVo>> uploads(@RequestParam("files") MultipartFile[] files, String businessId,String path,String userDefine ,Boolean ifPublic) throws Exception {
        BiFunction<MultipartFile[],UploadParam,List<FileInfoVo>> fun = (p1, p2) -> {
            try {
                List<FileInfoVo> fileList = new ArrayList<>();
                for (MultipartFile file : p1) {
                    FileInfoVo upload = ossServiceFactory.createFileService().upload(file, p2);
                    if(StringUtils.isNotBlank(upload.getUrl())) {
                        fileList.add(upload);
                    }
                }
                return fileList;
            } catch (Exception e) {
                return null;
            }
        };
        return ApiResult.responseFor(fun,files,new UploadParam(path,businessId,userDefine,ifPublic));
    }

    /**
     * 删除单个文件
     * @param id 文件id标识
     * @return
     */
    @DeleteMapping("/remove/{id}")
    @ApiOperation(value = "删除单个文件", notes = "删除单个文件")
    public ApiResult<Void> removeFile(@PathVariable String id){
        Consumer<String> consumer = p -> {
            FileService fileService = ossServiceFactory.createFileService();
            FileInfoVo delFile = fileService.getById(p);
            if(!ObjectUtils.isEmpty(delFile)){
                fileService.delete(delFile);
            }
        };
        return ApiResult.responseFor(consumer,id);
    }


    /**
     * 删除多个文件
     * @param ids 文件元数据ID列表
     * @return
     */
    @DeleteMapping("/removes")
    @ApiOperation(value = "批量删除文件", notes = "批量删除文件")
    public ApiResult<Void> removesFile(@RequestBody List<String> ids){
        Consumer<List<String>> consumer = p -> {
            FileService fileService = ossServiceFactory.createFileService();
            for (String id : p) {
                FileInfoVo delFile = fileService.getById(id);
                if(!ObjectUtils.isEmpty(delFile)) {
                    fileService.delete(delFile);
                }
            }
        };
        return ApiResult.responseFor(consumer,ids);
    }

    @PostMapping("/download/{id}")
    @ApiOperation(value = "下载单个文件", notes = "下载单个文件")
    public ApiResult download(@PathVariable String id , HttpServletResponse response) throws Exception {
        try {
            FileService ossService = ossServiceFactory.createFileService();
            FileInfoVo file = ossService.getById(id);
            if(ObjectUtils.isEmpty(file)) { return new ApiResult("9999","找不到对应的文件,下载文件失败" ); }
            byte[] data = ossService.download(file);
            response.reset();
            response.setHeader("Content-Disposition", "attachment; filename=\""+ java.net.URLEncoder.encode(file.getName(), "UTF-8")+"\"");
            response.addHeader("Content-Length", "" + data.length);
            response.setContentType("application/octet-stream; charset=UTF-8");

            //response.setContentType("application/vnd.ms-excel");
            //response.setCharacterEncoding("UTF-8");
            //response.setHeader("Content-disposition","attachment;filename="+new String(fileName.getBytes(),"iso-8859-1"));

            IOUtils.write(data, response.getOutputStream());
            return ApiResult.succeedResponse();
        } catch (Exception ex) {
            return new ApiResult("9999","download fail" + ex.getMessage());
        }
    }

    @PostMapping("/downloadpdf/{id}")
    @ApiOperation(value = "下载单个文件以pdf展现", notes = "下载单个文件以pdf展现")
    public ApiResult downloadWithPdf(@PathVariable String id , HttpServletResponse response) throws Exception {
        try {
            FileService ossService = ossServiceFactory.createFileService();
            FileInfoVo file = ossService.getById(id);
            if (ObjectUtils.isEmpty(file)) {
                return new ApiResult("9999", "找不到对应的文件,下载文件失败");
            }
            byte[] data = ossService.download(file);

            ByteArrayInputStream inputStream = new ByteArrayInputStream(data);

            byte[] fdfbytes = openOffice.officeToPdfo(inputStream, file.getName());

            response.reset();
            response.setHeader("Content-Disposition", "attachment; filename=\""+ java.net.URLEncoder.encode(file.getName().substring(0,file.getName().lastIndexOf("."))+".pdf", "UTF-8")+"\"");
            response.addHeader("Content-Length", "" + fdfbytes.length);
            response.setContentType("application/octet-stream; charset=UTF-8");

            IOUtils.write(fdfbytes, response.getOutputStream());
            return ApiResult.succeedResponse();


        }catch (Exception ex) {
            return new ApiResult("9999","download with pdf fail" + ex.getMessage());
        }
    }


    @PostMapping("/downloads")
    @ApiOperation(value = "批量下载文件以ZIP包的形式下载", notes = "批量下载文件以ZIP包的形式下载")
    public ApiResult downloadByBatch(@RequestBody List<String> ids, HttpServletRequest request, HttpServletResponse response) throws Exception {

        ByteArrayOutputStream outputStream = null;
        ZipOutputStream zip = null;
        int filesCount = 0;
        try {
            outputStream = new ByteArrayOutputStream();
            zip = new ZipOutputStream(outputStream);
            zip.setMethod(ZipOutputStream.DEFLATED);

            if (CollectionUtils.isNotEmpty(ids)) {
                FileService ossService = ossServiceFactory.createFileService();
                for (String sId : ids) {
                    FileInfoVo file = ossService.getById(sId);
                    if (null == file) {
                        continue;
                    }
                    filesCount++;
                    byte[] data = null;
                    data = ossService.download(file);
                    //添加到zip
                    zip.putNextEntry(new ZipEntry(file.getName()));
                    IOUtils.write(data, zip);
                    zip.closeEntry();
                }
                IOUtils.closeQuietly(zip);//在执行toByteArray();之前要先关闭ZipOutputStream对象
                byte[] data = outputStream.toByteArray();
                if (filesCount == 0) { return new ApiResult("9999", " 没有可供下载的文件,下载失败 "); }
                String zipFileName = UUID.randomUUID().toString().replace("-", "") + ".zip";
                response.reset();
                response.setHeader("Content-Disposition", "attachment; filename=" + zipFileName);
                response.addHeader("Content-Length", "" + data.length);
                response.setContentType("application/octet-stream; charset=UTF-8");
                response.setCharacterEncoding("UTF-8");
                IOUtils.write(data, response.getOutputStream());
            }

            return ApiResult.succeedResponse();

        } catch (Exception ex) {
            return new ApiResult("9999", "download fail" + ex.getMessage());
        } finally {
            if (Objects.nonNull(zip)) {
                zip.flush();
                zip.close();
            }
            if (Objects.nonNull(outputStream)) {
                outputStream.close();
            }
        }
    }
}
